1   /*
2    * Copyright 2016-2020 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.integration.jpa.dsl;
18  
19  import java.util.Collections;
20  import java.util.Map;
21  
22  import org.springframework.expression.Expression;
23  import org.springframework.integration.dsl.ComponentsRegistration;
24  import org.springframework.integration.dsl.MessageSourceSpec;
25  import org.springframework.integration.expression.ValueExpression;
26  import org.springframework.integration.jpa.core.JpaExecutor;
27  import org.springframework.integration.jpa.inbound.JpaPollingChannelAdapter;
28  import org.springframework.integration.jpa.support.parametersource.ParameterSource;
29  
30  /**
31   * A {@link MessageSourceSpec} for a {@link JpaPollingChannelAdapter}.
32   *
33   * @author Artem Bilan
34   *
35   * @since 5.0
36   */
37  public class JpaInboundChannelAdapterSpec
38  		extends MessageSourceSpec<JpaInboundChannelAdapterSpec, JpaPollingChannelAdapter>
39  		implements ComponentsRegistration {
40  
41  	protected final JpaExecutor jpaExecutor; // NOSONAR - final
42  
43  	protected JpaInboundChannelAdapterSpec(JpaExecutor jpaExecutor) {
44  		this.jpaExecutor = jpaExecutor;
45  		this.target = new JpaPollingChannelAdapter(this.jpaExecutor);
46  	}
47  
48  	/**
49  	 * Specify the class type which is being used for retrieving entities from the database.
50  	 * @param entityClass the entity {@link Class} to use
51  	 * @return the spec
52  	 */
53  	public JpaInboundChannelAdapterSpec entityClass(Class<?> entityClass) {
54  		this.jpaExecutor.setEntityClass(entityClass);
55  		return this;
56  	}
57  
58  	/**
59  	 * Specify a JPA query to perform persistent operation.
60  	 * @param jpaQuery the JPA query to use.
61  	 * @return the spec
62  	 */
63  	public JpaInboundChannelAdapterSpec jpaQuery(String jpaQuery) {
64  		this.jpaExecutor.setJpaQuery(jpaQuery);
65  		return this;
66  	}
67  
68  	/**
69  	 * Specify a native SQL query to perform persistent operation.
70  	 * @param nativeQuery the native SQL query to use.
71  	 * @return the spec
72  	 */
73  	public JpaInboundChannelAdapterSpec nativeQuery(String nativeQuery) {
74  		this.jpaExecutor.setNativeQuery(nativeQuery);
75  		return this;
76  	}
77  
78  	/**
79  	 * Specify a name a named JPQL based query or a native SQL query.
80  	 * @param namedQuery the name of the pre-configured query.
81  	 * @return the spec
82  	 */
83  	public JpaInboundChannelAdapterSpec namedQuery(String namedQuery) {
84  		this.jpaExecutor.setNamedQuery(namedQuery);
85  		return this;
86  	}
87  
88  	/**
89  	 * If set to 'true', the retrieved objects are deleted from the database upon
90  	 * being polled. May not work in all situations, e.g. for Native SQL Queries.
91  	 * @param deleteAfterPoll Defaults to 'false'.
92  	 * @return the spec
93  	 */
94  	public JpaInboundChannelAdapterSpec deleteAfterPoll(boolean deleteAfterPoll) {
95  		this.jpaExecutor.setDeleteAfterPoll(deleteAfterPoll);
96  		return this;
97  	}
98  
99  	/**
100 	 * If not set, this property defaults to <code>false</code>, which means that
101 	 * deletion occurs on a per object basis if a collection of entities is being
102 	 * deleted.
103 	 *<p>If set to 'true' the elements of the payload are deleted as a batch
104 	 * operation. Be aware that this exhibits issues in regards to cascaded deletes.
105 	 *<p>The specification 'JSR 317: Java Persistence API, Version 2.0' does not
106 	 * support cascaded deletes in batch operations. The specification states in
107 	 * chapter 4.10:
108 	 *<p>"A delete operation only applies to entities of the specified class and
109 	 * its subclasses. It does not cascade to related entities."
110 	 * @param deleteInBatch Defaults to 'false' if not set.
111 	 * @return the spec
112 	 */
113 	public JpaInboundChannelAdapterSpec deleteInBatch(boolean deleteInBatch) {
114 		this.jpaExecutor.setDeleteInBatch(deleteInBatch);
115 		return this;
116 	}
117 
118 	/**
119 	 * If set to {@code true} the {@link javax.persistence.EntityManager#flush()} will be called
120 	 * after persistence operation.
121 	 * Has the same effect, if the {@code flushSize} is specified to {@code 1}.
122 	 * For convenience in cases when the provided entity to persist is not an instance of {@link Iterable}.
123 	 * @param flush defaults to 'false'.
124 	 * @return the spec
125 	 */
126 	public JpaInboundChannelAdapterSpec flushAfterDelete(boolean flush) {
127 		this.jpaExecutor.setFlush(flush);
128 		return this;
129 	}
130 
131 	/**
132 	 * Specify a {@link ParameterSource} that would be used to provide additional parameters.
133 	 * @param parameterSource the {@link ParameterSource} to use.
134 	 * @return the spec
135 	 */
136 	public JpaInboundChannelAdapterSpec parameterSource(ParameterSource parameterSource) {
137 		this.jpaExecutor.setParameterSource(parameterSource);
138 		return this;
139 	}
140 
141 	/**
142 	 * This parameter indicates that only one result object shall be returned as
143 	 * a result from the executed JPA operation. If set to <code>true</code> and
144 	 * the result list from the JPA operations contains only 1 element, then that
145 	 * 1 element is extracted and returned as payload.
146 	 * @param expectSingleResult true if a single object is expected.
147 	 * @return the spec
148 	 */
149 	public JpaInboundChannelAdapterSpec expectSingleResult(boolean expectSingleResult) {
150 		this.jpaExecutor.setExpectSingleResult(expectSingleResult);
151 		return this;
152 	}
153 
154 	/**
155 	 * Set the maximum number of results expression. It has be a non null value
156 	 * Not setting one will default to the behavior of fetching all the records
157 	 * @param maxResults the maximum number of results to retrieve
158 	 * @return the spec
159 	 */
160 	public JpaInboundChannelAdapterSpec maxResults(int maxResults) {
161 		return maxResultsExpression(new ValueExpression<>(maxResults));
162 	}
163 
164 	/**
165 	 * Specify a SpEL expression for maximum number of results expression.
166 	 * Not setting one will default to the behavior of fetching all the records
167 	 * @param maxResultsExpression The maximum results expression.
168 	 * @return the spec
169 	 */
170 	public JpaInboundChannelAdapterSpec maxResultsExpression(String maxResultsExpression) {
171 		return maxResultsExpression(PARSER.parseExpression(maxResultsExpression));
172 	}
173 
174 	/**
175 	 * Specify a SpEL expression for maximum number of results expression.
176 	 * Not setting one will default to the behavior of fetching all the records
177 	 * @param maxResultsExpression The maximum results expression.
178 	 * @return the spec
179 	 */
180 	public JpaInboundChannelAdapterSpec maxResultsExpression(Expression maxResultsExpression) {
181 		this.jpaExecutor.setMaxResultsExpression(maxResultsExpression);
182 		return this;
183 	}
184 
185 	@Override
186 	public Map<Object, String> getComponentsToRegister() {
187 		return Collections.singletonMap(this.jpaExecutor, null);
188 	}
189 
190 }